package com.quarkus.service;

import com.quarkus.entity.User;
import io.smallrye.mutiny.Multi;
import io.smallrye.mutiny.TimeoutException;
import io.smallrye.mutiny.Uni;
import io.vertx.mutiny.pgclient.PgPool;
import io.vertx.mutiny.sqlclient.Row;
import io.vertx.mutiny.sqlclient.RowIterator;
import io.vertx.mutiny.sqlclient.SqlClientHelper;
import io.vertx.mutiny.sqlclient.SqlResult;
import io.vertx.mutiny.sqlclient.Tuple;

import javax.enterprise.context.ApplicationScoped;
import javax.inject.Inject;
import java.time.Duration;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Stream;
import java.util.stream.StreamSupport;

/**
 * @Author: TongRui乀
 * @Date: 2021/5/22 14:05
 * @description：
 */
@ApplicationScoped
public class UserService {

    @Inject
    PgPool pgPool;

    public Uni<List<User>> getList(){
        return this.pgPool.query("select * from t_user").execute()
                .onItem()
                .transform(rows -> {
                    Stream<Row> stream = StreamSupport.stream(rows.spliterator(), false);
                    Multi<Row> multi = Multi.createFrom().items(stream);
                    List<User> list = new ArrayList<>();
                    for (Row row : rows) {
                        User user = new User();
                        user.setId(row.getLong("id"));
                        user.setName(row.getString("name"));
                        list.add(user);
                    }
                    return list;
                });
    }

    public Uni<User> getById(Long id){
        return this.pgPool.preparedQuery("select * from t_user where id = $1").execute(Tuple.of(id))
                .onItem()
                .transformToUni(rows -> {
                    if(rows.size() == 0){
                        return Uni.createFrom().nullItem();
                    }
                    var row = rows.iterator().next();
                    var user = new User();
                    user.setId(row.getLong("id"));
                    user.setName(row.getString("name"));
                    return Uni.createFrom().item(user);
                });
    }

    public Uni<Integer> save(User user){

        return this.pgPool.begin()
                .onItem()
                .transformToUni(tx-> tx.preparedQuery("insert into t_user (name) values ( $1 ) returning id").execute(Tuple.of(user.getName()))
                        .onItem()
                        .transformToUni(rows -> {
                            if(rows.size() == 0){
                                return Uni.createFrom().item(-1);
                            }
                            return tx.commit().onItem()
                                    .transform(Void->rows.iterator().next().getInteger("id"));
                        })
                        .ifNoItem().after(Duration.ofMillis(2000))
                        .failWith(TimeoutException::new)
                        .onFailure()
                        .recoverWithUni(e->{
                            e.printStackTrace();
                            return tx.rollback()
                                    .onItem()
                                    .transform(Void -> -1);
                        })
                );
    }

    public Uni<Integer> update(User user){
        return SqlClientHelper.inTransactionUni(pgPool,tx-> tx.preparedQuery("update t_user set name = $1 where id = $2").execute(Tuple.of(user.getName(), user.getId()))
                .onItem()
//                .transform(SqlResult::rowCount))
                .transform(rows -> {
                    int a = 1/0;
                    return rows.rowCount();
                })
                .onFailure()
                .invoke(Throwable::printStackTrace));
    }

}
